﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;

namespace Pavilion.DesignerTool
{
    public class UndoRedoController : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public int UndoAmount { get { return undoStack.Count; } }
        public int RedoAmount { get { return redoStack.Count; } }
        public bool CanUndo { get { return UndoAmount > 0; } }
        public bool CanRedo { get { return RedoAmount > 0; } }
        public int MaxAmount { get; set; }

        private NotifiableCollection<IUndoRedoItem> undoStack;
        private NotifiableCollection<IUndoRedoItem> redoStack;

        public UndoRedoController()
        {
            undoStack = new NotifiableCollection<IUndoRedoItem>();
            redoStack = new NotifiableCollection<IUndoRedoItem>();

            MaxAmount = 30;

            undoStack.CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) => { OnPropertyChanged("CanUndo"); };
            redoStack.CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) => { OnPropertyChanged("CanRedo"); };
        }

        void undoStack_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            throw new NotImplementedException();
        }

        public void AddItem(IUndoRedoItem undoRedoItem)
        {
            redoStack.Clear();
            PushItem(undoStack, undoRedoItem);

            if (UndoAmount > MaxAmount)
                undoStack.RemoveAt(0);
        }

        public virtual void Undo()
        {
            if (UndoAmount == 0)
                return;

            IUndoRedoItem undoRedoItem = PopItem(undoStack);
            PushItem(redoStack, undoRedoItem);

            undoRedoItem.Undo();
        }

        public virtual void Redo()
        {
            if (RedoAmount == 0)
                return;

            IUndoRedoItem undoRedoItem = PopItem(redoStack);
            PushItem(undoStack, undoRedoItem);

            undoRedoItem.Redo();
        }

        private IUndoRedoItem PopItem(NotifiableCollection<IUndoRedoItem> undoRedoList)
        {
            IUndoRedoItem item = undoRedoList[undoRedoList.Count - 1];
            undoRedoList.Remove(item);
            return item;
        }

        private void PushItem(NotifiableCollection<IUndoRedoItem> undoRedoList, IUndoRedoItem item)
        {
            undoRedoList.Add(item);
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
